#!/usr/bin/python

# encoding : base num is 93
# 32bit value => 5 bytes
def dec_93(int_val):
    b0 = int_val % 93
    int_val /= 93
    b1 = int_val % 93
    int_val /= 93
    b2 = int_val % 93
    int_val /= 93
    b3 = int_val % 93
    int_val /= 93
    b4 = int_val % 93           # now int_val must < 93
    return [b4, b3, b2, b1, b0]


# display-able ascii char from 32 to 126 (0x20 - 0x7E), just use 93 of them, space not used, ~ is the flag of file end
# 93^n >= 256^m =>  n >= (log(256)/log(93))*m  => when m=4, n>=5
# input : 4 bytes(string, may not display-able), output:5bytes(string) which are display-able chars

def bin2disascii(bin_4b):
    int_val = 0
    for i in range(4):
        int_val |= (bin_4b[i]&0xff)<<(i*8)     # LSB first 
    orig_chars = dec_93(int_val)
    chars = [chr(i+0x21) for i in orig_chars]
    # return ''.join(chars)
    return chars

    
def disascii2bin(dis_chars):
    chars = [ord(i)-0x21 for i in dis_chars]
    int_val = 0
    for i in chars:
        int_val *= 93           # shift left
        int_val += i
    result = []
    for i in range(4):
        result.append(int_val & 0xff)
        int_val >>= 8
    return result
        
def int32_disascii(int_val):
    orig_chars = dec_93(int_val)
    chars = [chr(i+0x21) for i in orig_chars]
    return chars

    

if __name__ == "__main__":
    # bin_4b = [0x12, 0x34, 0x56, 0x78]
    # print "=============================="
    # print "original data : ", bin_4b
    # dis_chars = bin2disascii(bin_4b)
    # dis_chars = ''.join(dis_chars)
    # print "after encoding :", dis_chars
    # print "after decoding :", disascii2bin(dis_chars)
    # print "=============================="
    # print "0x12345678 => %s" % ''.join(int32_disascii(0x12345678))

    
    import sys
    fr = open(sys.argv[1], "rb")
    orig_data = fr.read()
    fr.close()
    f = open("result.txt", "w")    

    orig_data_length = len(orig_data)
    print "total length : ", orig_data_length
    header = []
    for i in range(4):
        header.append((orig_data_length>>(i*8)) & 0xff) # add 4 bytes, aligned
    orig_data = ''.join([chr(i) for i in header]) + orig_data
    if orig_data_length % 4:
        orig_data += 'X'*(4-(orig_data_length%4)) # make aligned
    orig_data_length = len(orig_data)
    
    # encoding
    encode_str = ''
    for i in range(0,orig_data_length,4):
        bin_4b = [ord(i) for i in orig_data[i:i+4]]
        dis_chars = ''.join(bin2disascii(bin_4b))
        encode_str += dis_chars

    encode_length = len(encode_str)
        
    max_valid_length = 200*1024
    fields = (encode_length+max_valid_length-1) / max_valid_length
    print "total %d segment of text" % fields
    for s in range(fields):
        if s == fields-1:                                                                                       
            line_max = encode_length - (fields-1)*max_valid_length
        else:
            line_max = max_valid_length
        # for i in range(0, line_max):
        #     idx = s*max_valid_length + i
        #     f.write(encode_str[idx])
        f.write(encode_str[s*max_valid_length:s*max_valid_length+line_max])
        f.write('\n'+'~'*100+'\n')

    f.close()                                                                                                   

#   print disascii2bin(encode_str[:5])
